package org.nlp2rdf.navigator.server;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
import org.nlp2rdf.navigator.api.KnowledgeBase;
import org.nlp2rdf.navigator.client.WorkerService;
import org.nlp2rdf.navigator.client.common.ClassificationCountResultDTO;
import org.nlp2rdf.navigator.client.common.ClassificationResultDTO;
import org.nlp2rdf.navigator.client.common.ConceptDTO;
import org.nlp2rdf.navigator.client.common.ExampleDTO;
import org.nlp2rdf.navigator.client.common.KnowledgeBaseDescriptorDTO;
import org.nlp2rdf.navigator.client.common.LearnedConceptDTO;
import org.nlp2rdf.navigator.client.common.RelatedConceptsDTO;
import org.nlp2rdf.navigator.client.common.SearchResultDTO;
import org.nlp2rdf.navigator.client.common.StoredConceptDTO;
import org.nlp2rdf.navigator.client.common.UserDTO;
import org.nlp2rdf.navigator.client.exception.NKEConceptParseException;
import org.nlp2rdf.navigator.client.exception.NKELearningException;
import org.nlp2rdf.navigator.client.exception.NKEQueryException;
import org.nlp2rdf.navigator.client.exception.NKERuntimeException;
import org.nlp2rdf.navigator.component.exception.ConceptSavingFailedException;
import org.nlp2rdf.navigator.util.ExceptionHelper;
import org.nlp2rdf.navigator.util.LogHelper;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

@SuppressWarnings("serial")
public class WorkerServletWrapper extends RemoteServiceServlet implements WorkerService {
	private static final Logger logger = Logger.getLogger(WorkerServletWrapper.class);

	public static String logging = LogHelper.touch();
	private static ApplicationContext context = null;
	// this variable has to be true while testing
	public static boolean testing = false;
	private static String TESTING_KB_LIST = "tiger,dbpedia";

	public static enum SessionAttributes {
		KbId, SessionObject
	};

	public ApplicationContext getApplicationContext() {
		if (context == null) {
			if (testing) {
				context = new ClassPathXmlApplicationContext(new String[] { "navigator_tiger.xml",
						"navigator_dbpedia.xml" });
			} else {
				context = new ClassPathXmlApplicationContext(getServletConfig().getInitParameter("springxml")
						.split(","));
			}
		}
		return context;

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.nlp2rdf.navigator.client.WorkerService#listAvailableKnowledgeBases()
	 */
	public Set<KnowledgeBaseDescriptorDTO> listAvailableKnowledgeBases() throws NKERuntimeException {
		Set<KnowledgeBaseDescriptorDTO> ret = null;
		try {
			Set<String> kbs = getKbList();
			ret = new HashSet<KnowledgeBaseDescriptorDTO>();
			for (String kbId : kbs) {
				KnowledgeBase s = KnowledgeBase.getInstance(getApplicationContext(), kbId);
				ret.add(s.getKnowledgeBaseDescriptorDTO());
			}
		} catch (RuntimeException e) {
			ExceptionHelper.handleRuntimeException(e, getClass());
		}
		return ret;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.nlp2rdf.navigator.client.WorkerService#changeKnowledgeBase(java.lang
	 * .String)
	 */
	public KnowledgeBaseDescriptorDTO changeKnowledgeBase(String kbId) throws NKERuntimeException {
		KnowledgeBaseDescriptorDTO ret = null;
		try {
			setSessionAttribute(SessionAttributes.KbId, kbId);
			KnowledgeBase s = KnowledgeBase.getInstance(getApplicationContext(), kbId);
			setSessionAttribute(SessionAttributes.SessionObject, s);
			ret = getTargetKnowledgeBase().getKnowledgeBaseDescriptorDTO();
		} catch (RuntimeException e) {
			ExceptionHelper.handleRuntimeException(e, getClass());
		}
		logger.info(getKbId() + " changeKnowledgeBase: " + kbId + " " + ret);
		return ret;

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.nlp2rdf.navigator.client.WorkerService#classifyCount(java.lang.String
	 * )
	 */
	public ClassificationCountResultDTO classifyCount(String conceptInKBSyntax)
			throws NKEConceptParseException, NKEQueryException, NKERuntimeException {
		return getTargetKnowledgeBase().classifyCount(conceptInKBSyntax);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.nlp2rdf.navigator.client.WorkerService#classify(java.lang.String,
	 * int, int)
	 */
	public ClassificationResultDTO classify(String conceptInKBSyntax, int limit, int offset)
			throws NKEConceptParseException, NKEQueryException, NKERuntimeException {
		return getTargetKnowledgeBase().classify(conceptInKBSyntax, limit, offset);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nlp2rdf.navigator.client.WorkerService#learn(java.util.List,
	 * java.util.List)
	 */
	public LearnedConceptDTO learn(List<ExampleDTO> pos, List<ExampleDTO> neg) throws NKELearningException,
			NKEQueryException, NKERuntimeException {

		return getTargetKnowledgeBase().learn(pos, neg);

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nlp2rdf.navigator.client.WorkerService#search(java.lang.String,
	 * java.lang.String, int)
	 */
	public SearchResultDTO search(String searchId, String searchString, int nrOfResults)
			throws NKEQueryException, NKERuntimeException {
		return getTargetKnowledgeBase().search(searchId, searchString, nrOfResults);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.nlp2rdf.navigator.client.WorkerService#generalise(org.nlp2rdf.navigator
	 * .client.common.LearningResultDTO)
	 */
	public List<LearnedConceptDTO> generalise(String conceptInKBSyntax) throws NKELearningException,
			NKEQueryException, NKERuntimeException {
		return getTargetKnowledgeBase().refine(conceptInKBSyntax, false);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.nlp2rdf.navigator.client.WorkerService#specialise(org.nlp2rdf.navigator
	 * .client.common.LearningResultDTO)
	 */
	public List<LearnedConceptDTO> specialise(String conceptInKBSyntax) throws NKELearningException,
			NKEQueryException, NKERuntimeException {
		return getTargetKnowledgeBase().refine(conceptInKBSyntax, true);
	}


	/**
	 * implementation of our fake login
	 */
	public UserDTO login(String username, String password) {
		UserDTO user = new UserDTO();
		user.setUsername(username);
		return user;
	}

	public List<StoredConceptDTO> getStoredConcepts() throws NKERuntimeException {
		return getTargetKnowledgeBase().getStoredConcepts();

	}

	public void saveConcept(LearnedConceptDTO learningResultDTO) throws NKERuntimeException {
		getTargetKnowledgeBase().saveConcept(learningResultDTO);
	}

	public RelatedConceptsDTO getRelatedConcepts(ConceptDTO learningResultDTO)
			throws NKERuntimeException, NKEQueryException {
		return getTargetKnowledgeBase().getRelatedConcepts(learningResultDTO);
	}

	public void incrementHitCount(StoredConceptDTO learningResultDTO) throws NKERuntimeException {
			getTargetKnowledgeBase().incrementHitCount(learningResultDTO);
	}

	/******************************************************************************************
	 * MANAGEMENT
	 *******************************************************************************************/

	public void terminateSession() {
		this.getThreadLocalRequest().getSession().removeAttribute(SessionAttributes.SessionObject.toString());
	}

	private String getKbId() {
		return (String) this.getThreadLocalRequest().getSession().getAttribute(
				SessionAttributes.KbId.toString());
	}

	/**
	 * @return the implemented session object
	 */
	private KnowledgeBase getTargetKnowledgeBase() {
		return (KnowledgeBase) this.getThreadLocalRequest().getSession().getAttribute(
				SessionAttributes.SessionObject.toString());
	}

	private void setSessionAttribute(SessionAttributes key, Object value) {
		HttpSession session = this.getThreadLocalRequest().getSession();
		session.setAttribute(key.toString(), value);
	}


	private Set<String> getKbList() {
		Set<String> kbList = new HashSet<String>();
		if (testing) {
			kbList.addAll(Arrays.asList(TESTING_KB_LIST.split(",")));
		} else {
			kbList.addAll(Arrays.asList(getServletConfig().getInitParameter("configurations").split(",")));
		}

		return kbList;
	}

	

	

	

}
